return-type function-name ( arg-type-1 arg-name-1, ... );
So, for example, the definition of SetWindowText looks like
BOOL SetWindowText ( HWND hWnd, LPCTSTR lpString );
In all cases, the arguments will be pushed starting with the rightmost argument. So to call the above function, you push the arguments before calling like this:
Push lpString
Push hWnd
Call SetWindowText
If you know what the types HWND and LPCTSTR mean, you will be able to convert the call to something like this:
push offset title1 ; address of new title string push dword ptr [ebp+8] ; hwnd from wndproc arg list call SetWindowText ; BOOL result (success/fail) in EAX ; arguments already popped by SetWindowTextThe above illustrates the stdcall calling convention used by most of the Win32 API functions. SetWindowText pops the arguments so that you won't need to. If it had used the cdecl calling convention, you would've needed to reset ESP with an extra instruction, as in the following:
add esp,8 ; pop two DWORD argumentsBecause SetWindowText uses a character string, the documentation is actually referring to two functions: SetWindowTextA, which uses a string of ANSI (8-bit) characters, and SetWindowTextW, which uses a string of (wide 16-bit) Unicode characters. In a C program, the include file windows.h has macros that automatically control and redefine these documented names to their Unicode/ANSI-specific ones. Thus the typical program will use only the documented names.
SetWindowText equ <SetWindowTextA> ; use ANSI in Win95You can, if you like, use a more elaborate technique to select which name you want as default.
interface_pointer -> function ( arglist )
The arguments are pushed in the reverse order, just like SDK functions. The extra argument is the interface pointer which is pushed last. Then we use it to access the vtable and call the function. You will need to know the exact storage order of the function addresses. Assuming interface_pointer is in memory, the instructions would be something like
; ... ; insert argument stacking here ; ... mov eax,[interface_pointer] push eax ; push interface pointer mov ecx,[eax] ; 1st dword of interface is vtable addr call [ecx+8] ; call the third function ; arguments already poppedString data in COM interfaces should always be in Unicode.
BYTE: char (signed), BYTE (unsigned)
WORD: short (signed), WORD (unsigned), ATOM (unsigned)
QWORD: double (floating point)
DWORD: int (signed), DWORD (unsigned), handles, pointers, and
hopefully everything else that's not a struct or related to the
previous types
push ebp mov ebp,esp sub esp,4 ; example for allocating one local DWORDthen you can access the first argument as [ebp+8], the second argument as [ebp+12], and so on. The size of each argument is a multiple of four bytes (DWORD). Most arguments are integers, handles, or pointers: all of these are only one DWORD in size.
mov esp,ebp pop ebpThe arguments can be popped off with the return instruction:
ret 16 ; example for four DWORD arguments